package org.loong.crypto.model.asn1.sm2;

import java.io.IOException;
import java.util.Enumeration;

import org.bouncycastle.asn1.ASN1BitString;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;

/**
 * SM2 publicKey.
 * 
 * <pre>
 * SM2PublicKey ::= SEQUENCE {
 *     algorithm AlgorithmIdentifier,
 *     publicKey BIT STRING 
 * }
 * </pre>
 */
public class SM2PublicKey extends ASN1Object {

    private AlgorithmIdentifier algId;

    private DERBitString publicKey;

    public SM2PublicKey(byte[] publicKey) {
        this.algId = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, GMObjectIdentifiers.sm2p256v1);
        this.publicKey = new DERBitString(publicKey);
    }
    
    public SM2PublicKey(ASN1Encodable publicKey) throws IOException {
        this.algId = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, GMObjectIdentifiers.sm2p256v1);
        this.publicKey = new DERBitString(publicKey);
    }

    public static SM2PublicKey getInstance(ASN1TaggedObject obj, boolean explicit) {
        return getInstance(ASN1Sequence.getInstance(obj, explicit));
    }

    public SM2PublicKey(ASN1Sequence seq) {
        if (seq.size() != 2) {
            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
        }

        Enumeration<?> e = seq.getObjects();
        this.algId = AlgorithmIdentifier.getInstance(e.nextElement());
        this.publicKey = DERBitString.convert(ASN1BitString.getInstance(e.nextElement()));
    }

    public static SM2PublicKey getInstance(Object obj) {
        if (obj instanceof SM2PublicKey) {
            return (SM2PublicKey) obj;
        } 
        
        if (obj != null) {
            return new SM2PublicKey(ASN1Sequence.getInstance(obj));
        }

        return null;
    }

    public AlgorithmIdentifier getAlgorithm() {
        return algId;
    }

    public ASN1Primitive parsePublicKey() throws IOException {
        return ASN1Primitive.fromByteArray(publicKey.getOctets());
    }

    public DERBitString getPublicKeyData() {
        return publicKey;
    }

    @Override
    public ASN1Primitive toASN1Primitive() {
        ASN1EncodableVector v = new ASN1EncodableVector(2);
        v.add(algId);
        v.add(publicKey);
        return new DERSequence(v);
    }
}
